package com.dabai.iot.core.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dabai.common.core.utils.DateUtils;
import com.dabai.common.redis.utils.RedisUtils;
import com.dabai.common.tdengine.core.TDEngineTemplate;
import com.dabai.common.tenant.helper.TenantHelper;
import com.dabai.iot.common.constant.IotKeyConstant;
import com.dabai.iot.core.cache.CacheKey;
import com.dabai.iot.core.dto.DevicePropertyQuery;
import com.dabai.iot.core.entity.DeviceEntity;
import com.dabai.iot.core.entity.ThingModelBlockEntity;
import com.dabai.iot.core.entity.ThingModelItemEntity;
import com.dabai.iot.core.model.DeviceProperty;
import com.dabai.iot.core.service.IDevicePropertyService;
import com.dabai.iot.core.service.IDeviceService;
import com.dabai.iot.core.service.IThingModelBlockService;
import com.dabai.iot.core.service.IThingModelItemService;
import com.dabai.iot.core.utils.IotTDSql;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设备属性记录 Service 实现类
 *
 * @author kev1n
 */
@Service
@RequiredArgsConstructor
public class DevicePropertyServiceImpl implements IDevicePropertyService {

    private final IDeviceService deviceService;
    private final IThingModelBlockService thingModelBlockService;
    private final IThingModelItemService thingModelItemService;
    private final TDEngineTemplate tdEngineTemplate;

    @Override
    public void saveLastPropertiesToRedis(Long deviceId, String jsonData) {
        String cacheKey = CacheKey.getPropertyKey(deviceId);
        String original = TenantHelper.ignore(() -> RedisUtils.getCacheObject(cacheKey));

        if (original == null) {
            TenantHelper.ignore(() -> RedisUtils.setCacheObject(cacheKey, jsonData));
            return;
        }

        // 解析JSON字符串
        JSONObject oldObj = JSON.parseObject(original);
        JSONObject newObj = JSON.parseObject(jsonData);

        // 获取blocks数组
        JSONArray oldBlocks = oldObj.getJSONArray(IotKeyConstant.BLOCKS);
        JSONArray newBlocks = newObj.getJSONArray(IotKeyConstant.BLOCKS);

        // 使用Map按blockIdentifier索引旧数据
        Map<String, JSONObject> blockMap = new HashMap<>();
        for (int i = 0; i < oldBlocks.size(); i++) {
            JSONObject block = oldBlocks.getJSONObject(i);
            String identifier = block.getString(IotKeyConstant.BLOCK_ID);
            blockMap.put(identifier, block);
        }

        // 合并新数据
        for (int i = 0; i < newBlocks.size(); i++) {
            JSONObject newBlock = newBlocks.getJSONObject(i);
            String identifier = newBlock.getString(IotKeyConstant.BLOCK_ID);

            if (blockMap.containsKey(identifier)) {
                // 合并已存在的block
                JSONObject oldBlock = blockMap.get(identifier);
                mergeBlocks(oldBlock, newBlock);
            } else {
                // 添加新block
                blockMap.put(identifier, newBlock);
            }
        }

        // 构建最终JSON
        JSONArray resultBlocks = new JSONArray();
        resultBlocks.addAll(blockMap.values());

        JSONObject result = new JSONObject();
        result.put(IotKeyConstant.BLOCKS, resultBlocks);
        TenantHelper.ignore(() -> RedisUtils.setCacheObject(cacheKey, result.toJSONString()));
    }

    private void mergeBlocks(JSONObject oldBlock, JSONObject newBlock) {
        // 合并properties
        JSONObject oldProps = oldBlock.getJSONObject(IotKeyConstant.PROPERTIES);
        JSONObject newProps = newBlock.getJSONObject(IotKeyConstant.PROPERTIES);
        newProps.keySet().forEach(key -> oldProps.put(key, newProps.get(key)));

        // 更新reportTime（取最新时间）
        long oldTime = oldBlock.getLongValue(IotKeyConstant.REPORT_TIME);
        long newTime = newBlock.getLongValue(IotKeyConstant.REPORT_TIME);
        if (newTime > oldTime) {
            oldBlock.put(IotKeyConstant.REPORT_TIME, newTime);
        }
    }

    @Override
    public List<DeviceProperty> getLastProperties(Long blockId, Long deviceId) {
        String cacheKey = CacheKey.getPropertyKey(deviceId);
        String propertyJsonStr = TenantHelper.ignore(() -> RedisUtils.getCacheObject(cacheKey));
        if (propertyJsonStr == null) {
            return List.of();
        }

        ThingModelBlockEntity modelBlock = thingModelBlockService.getById(blockId);
        if (modelBlock == null) {
            return List.of();
        }

        // 解析 JSON 字符串
        JSONObject propertyJson = JSON.parseObject(propertyJsonStr);

        // 获取 blocks 数组
        JSONArray blocksArray = propertyJson.getJSONArray(IotKeyConstant.BLOCKS);

        // 获取对应的 properties
        JSONObject propJson = null;
        for (int i = 0; i < blocksArray.size(); i++) {
            JSONObject block = blocksArray.getJSONObject(i);
            String blockIdentifier = block.getString(IotKeyConstant.BLOCK_ID);
            if (modelBlock.getBlockIdentifier().equals(blockIdentifier)) {
                propJson = block.getJSONObject(IotKeyConstant.PROPERTIES);
                break;
            }
        }

        if (propJson == null) {
            return List.of();
        }

        List<ThingModelItemEntity> modelItemList = thingModelItemService.lambdaQuery()
            .eq(ThingModelItemEntity::getBlockId, blockId)
            .orderByAsc(ThingModelItemEntity::getSort)
            .list();

        List<DeviceProperty> propertyList = new ArrayList<>(modelItemList.size());
        for (ThingModelItemEntity modelItem : modelItemList) {
            DeviceProperty property = new DeviceProperty();
            property.setItemId(modelItem.getId());
            property.setName(modelItem.getName());
            property.setIdentifier(modelItem.getIdentifier());
            property.setValue(propJson.getString(modelItem.getIdentifier()));
            property.setDataType(modelItem.getDataType());
            property.setScale(modelItem.getScale());
            property.setUnit(modelItem.getUnit());
            propertyList.add(property);
        }

        return propertyList;
    }

    @Override
    public IPage<Map<String, Object>> getPropertyLogPageFromTD(IPage<Map<String, Object>> page, DevicePropertyQuery propertyQuery) {
        DeviceEntity device = deviceService.getDeviceCacheById(propertyQuery.getDeviceId());
        if (device == null) {
            return page;
        }

        ThingModelItemEntity modelItem = thingModelItemService.getById(propertyQuery.getItemId());
        if (modelItem == null) {
            return page;
        }

        String tableName = IotTDSql.getDevicePropertyTableName(device.getProductKey(), modelItem.getBlockIdentifier(), device.getDeviceSn());

        // sql 拼接
        String sql = "SELECT ts, ${itemField} FROM `${tableName}` WHERE 1 = 1 ";
        // sql 参数
        Map<String, Object> params = new HashMap<>(8);
        params.put("itemField", modelItem.getIdentifier());
        params.put("tableName", tableName);
        // 时间筛选
        if (propertyQuery.getQueryStartTime() != null) {
            sql += " and ts >= '${time1}'";
            params.put("time1", DateUtils.formatDateTime(propertyQuery.getQueryStartTime()));
        }
        if (propertyQuery.getQueryEndTime() != null) {
            sql += " and ts <= '${time2}'";
            params.put("time2", DateUtils.formatDateTime(propertyQuery.getQueryEndTime()));
        }

        // 排序
        sql += " order by ts desc";
        return tdEngineTemplate.getPageBySql(page, sql, params);
    }
}
